home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / mint / shells / sh03src.zoo / sh-pl03 / sh / redir.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-05-23  |  8.1 KB  |  365 lines

  1. /*-
  2.  * Copyright (c) 1991 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * This code is derived from software contributed to Berkeley by
  6.  * Kenneth Almquist.
  7.  *
  8.  * Redistribution and use in source and binary forms, with or without
  9.  * modification, are permitted provided that the following conditions
  10.  * are met:
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  * 2. Redistributions in binary form must reproduce the above copyright
  14.  *    notice, this list of conditions and the following disclaimer in the
  15.  *    documentation and/or other materials provided with the distribution.
  16.  * 3. All advertising materials mentioning features or use of this software
  17.  *    must display the following acknowledgement:
  18.  *    This product includes software developed by the University of
  19.  *    California, Berkeley and its contributors.
  20.  * 4. Neither the name of the University nor the names of its contributors
  21.  *    may be used to endorse or promote products derived from this software
  22.  *    without specific prior written permission.
  23.  *
  24.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  25.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  28.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  29.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  30.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  31.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  33.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  34.  * SUCH DAMAGE.
  35.  */
  36.  
  37. #ifndef lint
  38. static char sccsid[] = "@(#)redir.c    5.1 (Berkeley) 3/7/91";
  39. #endif /* not lint */
  40.  
  41. /*
  42.  * Code for dealing with input/output redirection.
  43.  */
  44.  
  45. #include "shell.h"
  46. #include "nodes.h"
  47. #include "jobs.h"
  48. #include "expand.h"
  49. #include "redir.h"
  50. #include "output.h"
  51. #include "memalloc.h"
  52. #include "error.h"
  53. #include <signal.h>
  54. #include <fcntl.h>
  55. #include <errno.h>
  56.  
  57.  
  58. #define EMPTY -2        /* marks an unused slot in redirtab */
  59. #define PIPESIZE 4096        /* amount of buffering in a pipe */
  60.  
  61.  
  62. MKINIT
  63. struct redirtab {
  64.     struct redirtab *next;
  65.     short renamed[10];
  66. };
  67.  
  68.  
  69. MKINIT struct redirtab *redirlist;
  70.  
  71. /* We keep track of whether or not fd0 has been redirected.  This is for
  72.    background commands, where we want to redirect fd0 to /dev/null only
  73.    if it hasn't already been redirected.  */
  74. int fd0_redirected = 0;
  75.  
  76. #ifdef __STDC__
  77. STATIC void openredirect(union node *, char *);
  78. STATIC int openhere(union node *);
  79. #else
  80. STATIC void openredirect();
  81. STATIC int openhere();
  82. #endif
  83.  
  84.  
  85.  
  86. /*
  87.  * Process a list of redirection commands.  If the REDIR_PUSH flag is set,
  88.  * old file descriptors are stashed away so that the redirection can be
  89.  * undone by calling popredir.  If the REDIR_BACKQ flag is set, then the
  90.  * standard output, and the standard error if it becomes a duplicate of
  91.  * stdout, is saved in memory.
  92.  */
  93.  
  94. void
  95. redirect(redir, flags)
  96.     union node *redir;
  97.     int flags;
  98.     {
  99.     union node *n;
  100.     struct redirtab *sv;
  101.     int i;
  102.     int fd;
  103.     char memory[10];        /* file descriptors to write to memory */
  104.  
  105.     for (i = 10 ; --i >= 0 ; )
  106.         memory[i] = 0;
  107.     memory[1] = flags & REDIR_BACKQ;
  108.     if (flags & REDIR_PUSH) {
  109.         sv = ckmalloc(sizeof (struct redirtab));
  110.         for (i = 0 ; i < 10 ; i++)
  111.             sv->renamed[i] = EMPTY;
  112.         sv->next = redirlist;
  113.         redirlist = sv;
  114.     }
  115.     for (n = redir ; n ; n = n->nfile.next) {
  116.         fd = n->nfile.fd;
  117.         if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) {
  118.             INTOFF;
  119.             if ((i = copyfd(fd, 10)) != EMPTY) {
  120.                 sv->renamed[fd] = i;
  121.                 close(fd);
  122.             }
  123.             INTON;
  124.             if (i == EMPTY)
  125.                 error("Out of file descriptors");
  126.         } else {
  127.             close(fd);
  128.         }
  129.         if (fd == 0)
  130.             fd0_redirected++;
  131.         openredirect(n, memory);
  132.     }
  133.     if (memory[1])
  134.         out1 = &memout;
  135.     if (memory[2])
  136.         out2 = &memout;
  137. }
  138.  
  139.  
  140. STATIC void
  141. openredirect(redir, memory)
  142.     union node *redir;
  143.     char memory[10];
  144.     {
  145.     int fd = redir->nfile.fd;
  146.     char *fname;
  147.     int f;
  148.  
  149.     /*
  150.      * We suppress interrupts so that we won't leave open file
  151.      * descriptors around.  This may not be such a good idea because
  152.      * an open of a device or a fifo can block indefinitely.
  153.      */
  154.     INTOFF;
  155.     memory[fd] = 0;
  156.     switch (redir->nfile.type) {
  157.     case NFROM:
  158.         fname = redir->nfile.expfname;
  159.         if ((f = open(fname, O_RDONLY)) < 0)
  160.             error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
  161. movefd:
  162.         if (f != fd) {
  163.             copyfd(f, fd);
  164.             close(f);
  165.         }
  166.         break;
  167.     case NTO:
  168.         fname = redir->nfile.expfname;
  169. #ifdef O_CREAT
  170.         if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
  171.             error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
  172. #else
  173.         if ((f = creat(fname, 0666)) < 0)
  174.             error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
  175. #endif
  176.         goto movefd;
  177.     case NAPPEND:
  178.         fname = redir->nfile.expfname;
  179. #ifdef O_APPEND
  180.         if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
  181.             error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
  182. #else
  183.         if ((f = open(fname, O_WRONLY)) < 0
  184.          && (f = creat(fname, 0666)) < 0)
  185.             error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
  186.         lseek(f, 0L, 2);
  187. #endif
  188.         goto movefd;
  189.     case NTOFD:
  190.     case NFROMFD:
  191.         if (redir->ndup.dupfd >= 0) {    /* if not ">&-" */
  192.             if (memory[redir->ndup.dupfd])
  193.                 memory[fd] = 1;
  194.             else
  195.                 copyfd(redir->ndup.dupfd, fd);
  196.         }
  197.         break;
  198.     case NHERE:
  199.     case NXHERE:
  200.         f = openhere(redir);
  201.         goto movefd;
  202.     default:
  203.         abort();
  204.     }
  205.     INTON;
  206. }
  207.  
  208.  
  209. /*
  210.  * Handle here documents.  Normally we fork off a process to write the
  211.  * data to a pipe.  If the document is short, we can stuff the data in
  212.  * the pipe without forking.
  213.  */
  214.  
  215. STATIC int
  216. openhere(redir)
  217.     union node *redir;
  218.     {
  219.     int pip[2];
  220.     int len;
  221.  
  222.     if (pipe(pip) < 0)
  223.         error("Pipe call failed");
  224.     if (redir->type == NHERE) {
  225.         len = strlen(redir->nhere.doc->narg.text);
  226.         if (len <= PIPESIZE) {
  227.             xwrite(pip[1], redir->nhere.doc->narg.text, len);
  228.             goto out;
  229.         }
  230.     }
  231.     if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
  232.         close(pip[0]);
  233.         signal(SIGINT, SIG_IGN);
  234.         signal(SIGQUIT, SIG_IGN);
  235.         signal(SIGHUP, SIG_IGN);
  236. #ifdef SIGTSTP
  237.         signal(SIGTSTP, SIG_IGN);
  238. #endif
  239.         signal(SIGPIPE, SIG_DFL);
  240.         if (redir->type == NHERE)
  241.             xwrite(pip[1], redir->nhere.doc->narg.text, len);
  242.         else
  243.             expandhere(redir->nhere.doc, pip[1]);
  244.         _exit(0);
  245.     }
  246. out:
  247.     close(pip[1]);
  248.     return pip[0];
  249. }
  250.  
  251.  
  252.  
  253. /*
  254.  * Undo the effects of the last redirection.
  255.  */
  256.  
  257. void
  258. popredir() {
  259.     register struct redirtab *rp = redirlist;
  260.     int i;
  261.  
  262.     for (i = 0 ; i < 10 ; i++) {
  263.         if (rp->renamed[i] != EMPTY) {
  264.             if (i == 0)
  265.                 fd0_redirected--;
  266.             close(i);
  267.             if (rp->renamed[i] >= 0) {
  268.                 copyfd(rp->renamed[i], i);
  269.                 close(rp->renamed[i]);
  270.             }
  271.         }
  272.     }
  273.     INTOFF;
  274.     redirlist = rp->next;
  275.     ckfree(rp);
  276.     INTON;
  277. }
  278.  
  279.  
  280.  
  281. /*
  282.  * Undo all redirections.  Called on error or interrupt.
  283.  */
  284.  
  285. #ifdef mkinit
  286.  
  287. INCLUDE "redir.h"
  288.  
  289. RESET {
  290.     while (redirlist)
  291.         popredir();
  292. }
  293.  
  294. SHELLPROC {
  295.     clearredir();
  296. }
  297.  
  298. #endif
  299.  
  300.  
  301. /*
  302.  * Discard all saved file descriptors.
  303.  */
  304.  
  305. void
  306. clearredir() {
  307.     register struct redirtab *rp;
  308.     int i;
  309.  
  310.     for (rp = redirlist ; rp ; rp = rp->next) {
  311.         for (i = 0 ; i < 10 ; i++) {
  312.             if (rp->renamed[i] >= 0) {
  313.                 close(rp->renamed[i]);
  314.             }
  315.             rp->renamed[i] = EMPTY;
  316.         }
  317.     }
  318. }
  319.  
  320.  
  321.  
  322. /*
  323.  * Copy a file descriptor, like the F_DUPFD option of fcntl.  Returns -1
  324.  * if the source file descriptor is closed, EMPTY if there are no unused
  325.  * file descriptors left.
  326.  */
  327.  
  328. int
  329. copyfd(from, to) {
  330. #ifdef F_DUPFD
  331.     int newfd;
  332.  
  333.     newfd = fcntl(from, F_DUPFD, to);
  334.     if (newfd < 0 && errno == EMFILE)
  335.         return EMPTY;
  336.     return newfd;
  337. #else
  338.     char toclose[32];
  339.     int i;
  340.     int newfd;
  341.     int e;
  342.  
  343.     for (i = 0 ; i < to ; i++)
  344.         toclose[i] = 0;
  345.     INTOFF;
  346.     while ((newfd = dup(from)) >= 0 && newfd < to)
  347.         toclose[newfd] = 1;
  348.     e = errno;
  349.     for (i = 0 ; i < to ; i++) {
  350.         if (toclose[i])
  351.             close(i);
  352.     }
  353.     INTON;
  354.     if (newfd < 0 && e == EMFILE)
  355.         return EMPTY;
  356.     return newfd;
  357. #endif
  358. }
  359.  
  360. /* Return true if fd 0 has already been redirected at least once.  */
  361. int
  362. fd0_redirected_p () {
  363.     return fd0_redirected != 0;
  364. }
  365.